(function () {
    // 数据模型
    const data = [{
        id: 1,
        count: 2,
        price: 12.5
    }, {
        id: 2,
        count: 0,
        price: 10.5
    }, {
        id: 3,
        count: 3,
        price: 8.5
    }, {
        id: 4,
        count: 0,
        price: 8
    }, {
        id: 5,
        count: 0,
        price: 14.5
    }];

    /* 获取需要操作的DOM元素：想要操作谁，就先获取谁 */
    let computedBox = document.querySelector('#computedBox'),
        topBox = computedBox.querySelector('.top'),
        [subCountBox, subPriceBox, subMaxBox] = Array.from(computedBox.querySelectorAll('.bottom span'));
    let btnBoxList = [],
        pronumBoxList = [],
        emBoxList = [];

    /* 实现数据动态绑定：根据DATA动态创建对应的行 */
    const render = function render() {
        let str = ``;
        data.forEach((item, index) => {
            let { count, price } = item;
            str += `<div class="hang" index="${index}">
                <i class="minus"></i>
                <span class="pronum">${count}</span>
                <i class="add"></i>
                <span class="info">
                    单价：${price}元 &nbsp;&nbsp;
                    小计：<em>${count * price}</em>元
                </span>
            </div>`;
        });
        topBox.innerHTML = str;
        // 获取动态绑定的DOM元素
        btnBoxList = Array.from(topBox.querySelectorAll('i'));
        pronumBoxList = Array.from(topBox.querySelectorAll('.pronum'));
        emBoxList = Array.from(topBox.querySelectorAll('em'));
    };
    render();

    /* 计算总计信息：根据每一行的数据，计算出总计的信息 */
    const computed = function computed() {
        let counts = 0,
            prices = 0,
            max = [0];
        pronumBoxList.forEach((pronumBox, index) => {
            let count = +pronumBox.innerHTML;
            counts += count;

            let emBox = emBoxList[index],
                subtotal = +emBox.innerHTML;
            prices += subtotal;

            if (count > 0) {
                max.push(data[index].price);
            }
        });
        subCountBox.innerHTML = counts;
        subPriceBox.innerHTML = prices;
        subMaxBox.innerHTML = Math.max(...max);
    };
    computed();

    /* 点击加减按钮，控制当前行的数据改变「以及重新计算总计信息」 */
    btnBoxList.forEach(btnBox => {
        // 循环给每一个按钮做事件绑定
        btnBox.onclick = function () {
            // 获取点击按钮所在行的索引
            let index = +this.parentNode.getAttribute('index');
            // 获取这一行的数量框、数量、单价、小计框、点击按钮类型
            let pronumBox = pronumBoxList[index],
                emBox = emBoxList[index],
                count = +pronumBox.innerHTML,
                price = data[index].price,
                type = this.className;
            // 控制每一行数据的变更
            if (type === 'minus') {
                count--;
                if (count < 0) count = 0;
            } else {
                count++;
            }
            pronumBox.innerHTML = count;
            emBox.innerHTML = count * price;
            // 重新计算总计信息
            computed();
        };
    });
})();

//======================================
/*
 知识点：自定义属性的操作
   设置在HTML的结构上
     元素.setAttribute('index',1)
     元素.getAttribute('index')
     元素.removeAttribute('index')

   设置在元素对象的堆内存中「给堆内存设置新的键值对」
     元素.index=1
     元素.index
     delete 元素.index
*/

//======================================
/*
 ES6提供了字符串拼接的新方案：模板字符串 「反引号 ``」
   基于 ${} 嵌入JS表达式！
   + 变量
   + 值
   + JS运算，例如：1+1
   + ...
 非常方便字符串拼接，不需要考虑单双引号问号，也不需要考虑换行问题！！
 */
/* let count = 10;
let str = `<div class="hang">
    <i class="minus"></i>
    <span class="pronum">${count}</span>
</div>`; */

/* let name = '赵继杨';
let age = 72;
let str1 = "我叫做" + name + "，今年" + age + "岁啦，我是一名前端工程师！";
let str2 = `我叫做${name}，今年${age}岁，我是一名前端工程师！`;
console.log(str1); */

//======================================
/*
 ES6中新提供的一种语法：解构赋值「可以对数组&对象等做解构赋值」
   让等号左边出现和右侧“值”相同的结构，然后在左侧声明多个变量，快速解构出右侧值中的某一部分!
   解构赋值的最大作用:快速取值！！
   还有一些其它的作用，例如：交换变量值
 */

/* let a = 12,
    b = 13;
[b, a] = [a, b]; //[12,13]
console.log(a, b); */

/* a = a + b; //25
b = a - b;
a = a - b;
console.log(a, b); */

/* let c = a;
a = b;
b = c;
console.log(a, b); */

//----------------
/* let obj = {
    name: '珠峰',
    list: [
        900,
        {
            math: 100,
            chinese: 120
        }
    ]
};
// 我们想要获取 name「变量名userName」、age「默认值13」、chinese
let {
    name: userName,
    age = 13,
    list: [, { chinese }]
} = obj;
console.log(userName, age, chinese); //珠峰 13 120 */

//----------------
// 对象的解构赋值：去对象中查找和变量“同名”的属性值，无需关注顺序问题
/* let obj = {
    name: '珠峰',
    age: 13,
    class: 3,
    boy: 12,
    girl: 6
}; */
/* let { a, b } = obj;
console.log(a, b); //undefined * 2 */

/* let { name, age } = obj;
console.log(name, age);//珠峰 13 */

/* let { girl, boy } = obj;
console.log(girl, boy);//6 12 */

/* // 进行重命名：指定一个新的变量名，去获取对象中某个属性的值
let { class: class2 } = obj;
// var class2 = obj.class;
console.log(class2); //3 */

/* // 解构赋值的同时设置默认值:如果没有这个成员则使用默认值
let { sex = '男' } = obj;
console.log(sex); //'男' */

//----------------
// 数组的解构赋值：直接声明变量获取对应位置的值
/* let arr = [10, 20, 30, 40];
let [a, b, c, d] = arr;
console.log(a, b, c, d); */

/* let [a, , , b] = [10, 20, 30, 40];
console.log(a, b);  //10 40 */

/* let [a, b] = [10, 20, 30, 40];
console.log(a, b); //10 20 */

/* let [a, ...b] = [10, 20, 30, 40];
console.log(a, b); //10 [20, 30, 40] */

/* let [a, , [, , [, b]]] = [10, 20, [30, 40, [50, 60]]];
console.log(a, b); //10 60 */

//======================================
/*
 基于querySelectorAll获取的结果是一个NodeList节点集合「类数组：结构和数组类似，但是并不是Array的实例，原型链也无法找到Array.prototype」
   + 类数组获取某个成员 : 类数组[索引]
   + 类数组无法直接使用数组的办法

 鸭式辨型(鸭子类型)：类数组不是数组，无法直接使用数组的办法，而鸭式辨型的目的是让“类数组可以使用数组办法”
   无法直接使用的原因：类数组的原型链找不到Array.prototype，所以无法使用数组提供的方法
   @1 把类数组转换为数组
     + 最笨的办法：迭代类数组每一项，赋值给新数组
     + 借用数组原型上的slice方法，实现把类数组转换为数组
       + 找到数组原型上的slice，让其执行的时候，slice中的this指向类数组
       + 在slice内部的代码中，可以把类似组转换为数组
     + 基于ES6+的Array.from处理「弊端：不兼容IE」

   @2 修改类数组的原型指向：类数组的.__proto__=Array.prototype
     IE中禁止操作__proto__，我们需要基于 Object.setPrototypeOf 来处理！！
     弊端：只能兼容到IE11

   @3 方法借用：类数组直接借用数组原型上的方法，来实现相关的操作
     原理：类数组和数组结构太相似了，数组大部分方法的内置源码中，对数组的操作也同样适用于类数组，所以我们只要把数组方法执行，让方法中的this指向类数组，则也同样可以实现对应的效果！！
     + [].xxx.call(类数组,...)
       Array.prototype.xxx.call(类数组,...)
     + 把需要借用的方法赋值给类数组对象的私有属性即可
 */

/* // 标准的类数组
let obj = {
    0: 10,
    1: 20,
    2: 30,
    length: 3,
    forEach: Array.prototype.forEach
}; */
/* [].forEach.call(obj, (item, index) => {
    console.log(item, index);
}); */
/* obj.forEach((item, index) => {
    console.log(item, index);
}); */

//-----------------
/* let arr = Array.from(obj);
console.log(arr); */

/*
// 相对合适的办法
// let arr = Array.prototype.slice.call(obj);
let arr = [].slice.call(obj);
console.log(arr);
*/
/* Array.prototype.slice = function slice() {
    // this->a  创建一个新数组，并且把a中的每一项赋值给新数组，返回新数组
    let arr = [];
    for (let i = 0; i < this.length; i++) {
        arr.push(this[i]);
    }
    return arr;
};
let a = [10, 20, 30, 40];
let b = a.slice();
console.log(b, b === a); */

/*
// 最笨的办法
let arr = [];
for (let i = 0; i < obj.length; i++) {
    arr.push(obj[i]);
}
console.log(arr);
*/

//----------------
/* Object.setPrototypeOf(obj, Array.prototype); //obj.__proto__ = Array.prototype
obj.push(40);
console.log(obj); */